#pragma once

#include <AVUIObject.h>
#include <AVUICollectionView.h>
#include <AVUIIComparer.h>
#include <AVUIObjectCollection.h>

namespace AVUI {

class ItemCollection;

class ListCollectionView : public CollectionView, public IComparer
{
public:
    DECLARE_ELEMENT(ListCollectionView, CollectionView);

    ListCollectionView(Object* pCollection);

	virtual bool Contains(Object* pItem) { VerifyRefreshNotDeferred(); return InternalContains(pItem); }
	virtual ObjectPtr GetItemAt(int index) { VerifyRefreshNotDeferred(); return InternalItemAt(index); }
	virtual int IndexOf(Object* pObject) { VerifyRefreshNotDeferred(); return InternalIndexOf(pObject); }

	virtual bool get_CanFilter() { return true; }
	virtual bool get_CanGroup() { return true; }
	virtual bool get_CanSort() { return true; }
	virtual int get_Count()
	{
		VerifyRefreshNotDeferred();
		return get_InternalCount();
	}

	IComparer* get_CustomSort() { return m_pCustomSort; }
	void set_CustomSort(Object* pCustomSort)
	{
		m_pCustomSort = interface_cast<IComparer>(pCustomSort);
		m_pCustomSortObject = pCustomSort;
		SetSortDescriptions(NULL);
		RefreshOrDefer();
	}

	// GroupBySelector
	// GroupDescriptions
	// Groups
	// IsDataInGroupOrder

	virtual bool get_IsEmpty() { return get_InternalCount() == 0; }
	virtual SortDescriptionCollection* get_SortDescriptions();
	virtual bool MoveCurrentToPosition(int position);

	virtual bool PassesFilter(Object* pItem);

protected:

	virtual int Compare(Object* pO1, Object* pO2);
    virtual Object* get_Object() { return Object::get_Object(); }

	virtual ObjectPtr GetEnumerator() { VerifyRefreshNotDeferred(); return InternalGetEnumerator(); }
	//protected override void OnBeginChangeLogging(NotifyCollectionChangedEventArgs args)
	//OnGroupByChanged
	//private void OnGroupChanged(object sender, NotifyCollectionChangedEventArgs e)
	// private void OnGroupDescriptionChanged(object sender, EventArgs e)
	virtual void ProcessCollectionChanged(CollectionChangedEventArgs* pArgs);
	virtual void RefreshOverride();
	
	

	bool InternalContains(Object* pItem);
	ObjectPtr InternalGetEnumerator();
	int InternalIndexOf(Object* pItem);
	ObjectPtr InternalItemAt(int index);

	IComparer* get_ActiveComparer() { return m_pActiveComparer; }
	void set_ActiveComparer(Object* pActiveComparer)
	{
		m_pActiveComparer = interface_cast<IComparer>(pActiveComparer);
		m_pActiveComparerObject = pActiveComparer;
		// this._group.ActiveComparer = value;
	}

	ObjectPredicate* get_ActiveFilter() { return m_pActiveFilter; }
	void set_ActiveFilter(ObjectPredicate* pActiveFilter) { m_pActiveFilter = pActiveFilter; }

	int get_InternalCount()
	{
		/*
		if(get_IsGrouping())
		{
			return m_pGroup->get_ItemCount();
		}
		*/
		return get_InternalList()->get_Count();
	}

	ICollection* get_InternalList() { return m_pInternalList; }
	Object* get_InternalListObject() { return m_pInternalListObject; }
	bool get_IsGrouping() { return m_isGrouping; }

	TRefCountedPtr< ItemStructList< TRefCountedPtr<Object> > > get_ShadowCollection() { return m_pShadowCollection; }
	void set_ShadowCollection(TRefCountedPtr< ItemStructList< TRefCountedPtr<Object> > > pShadowCollection) { m_pShadowCollection = pShadowCollection; }

	bool get_UsesLocalArray() { return get_ActiveComparer() != NULL || get_ActiveFilter() != NULL; }

private:

	void AddItemToGroups(Object* pItem);
	int AdjustBefore(NotifyCollectionChangedAction::Enum action, Object* pItem, int index);
	void AdjustCurrencyForAdd(int index);
	void AdjustCurrencyForMove(int oldIndex, int newIndex);
	void AdjustCurrencyForReplace(int index);
	void AdjustCurrencyForRemove(int index);
	void AdjustShadowCopy(CollectionChangedEventArgs* pArgs);
	void MoveCurrencyOffDeletedElement(int oldCurrentPosition);
	void OnPropertyChanged(Property* pProperty);
	//void PrepareGroups();
	ObjectPtr PrepareLocalArray(ICollection* pList);
	void PrepareSortAndFilter(ICollection* pList);
	// void PrepareXmlComparer()
	//void RemoveItemFromGroups(object item);
	void SetSortDescriptions(SortDescriptionCollection* pDescriptions);
	void SortDescriptionsChanged(Object* pSender, CollectionChangedEventArgs* pArgs);
	void ValidateCollectionChangedEventArgs(CollectionChangedEventArgs* e) { }
 

 



	bool get_CanGroupNamesChange() { return true; }
	bool get_HasSortDescriptions();
	bool get_IsCurrentInView() { return (0 <= get_CurrentPosition() && get_CurrentPosition() < get_InternalCount()); }

	IComparer* m_pActiveComparer;
	TRefCountedPtr<Object> m_pActiveComparerObject;

	TRefCountedPtr<ObjectPredicate> m_pActiveFilter;
	bool m_applyChangeToShadow;
	bool m_currentElementWasRemoved;
	IComparer* m_pCustomSort;
	TRefCountedPtr<Object> m_pCustomSortObject;
	// CollectionViewGroupRoot* m_pGroup;
	ICollection* m_pInternalList;
	TRefCountedPtr<Object> m_pInternalListObject;
	bool m_isGrouping;
	TRefCountedPtr< ItemStructList< TRefCountedPtr<Object> > > m_pShadowCollection;
	TRefCountedPtr<SortDescriptionCollection> m_pSort;
	static const int m_unknownIndex = -1;

};

}; // namespace AVUI
